﻿using System;
using System.Collections.Generic;
using System.Linq;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity;
using static T.FAS.Runtime.Metadata.Entity.DataModel.DataQueryRefSchemaEntity;
//using BigDataColumn = T.BDP.DCP.Metadata.Entity.DataColumn;
//using T.BDP.DCP.Metadata.Entity;
using T.ServiceComponent.I18N.Service;

namespace T.FAS.Runtime.Metadata.Entity.DataModel
{
    public partial class DataQuery
    {
        public const string RefSchemaPrefix = "Schema.DQ";
        public const string ExprColumnNameSpace = nameof(DataQueryRefSchemaEntity.__UserDefineColumns);
        public const string AggAndGroupColumnNameSpace = nameof(DataQueryRefSchemaEntity.__AggreAndGroupColumns);
        public const string Sources = nameof(DataQueryRefSchemaEntity.Sources);
        public const string Columns = nameof(DQSource.Columns);
        public const string SubDQ = nameof(DataQueryRefSchemaEntity.SubDQ);
        public const string Param = nameof(DataQueryRefSchemaEntity.Param);

        private const string IsSDO = CommonConst.TAttributeExtProperties.IsSDO;
        private const string SDOID = CommonConst.TAttributeExtProperties.SDOID;
        private const string IsStateField = CommonConst.TAttributeExtProperties.IsStateField;
        private const string IsTimestamp = CommonConst.TAttributeExtProperties.IsTimestamp;
        private const string IsSystem = CommonConst.TAttributeExtProperties.IsSystem;
        private const string IsParalanguage = CommonConst.TAttributeExtProperties.IsParalanguage;
        private const string IsInternational = CommonConst.TAttributeExtProperties.IsInternational;
        private const string IsMaskingColumn = CommonConst.TAttributeExtProperties.IsMaskingColumn;
        private const string OriginMaskingColumn = CommonConst.TAttributeExtProperties.OriginMaskingColumn;
        private const string MaskRule = CommonConst.TAttributeExtProperties.MaskRule;
        private const string IsEnableMasking = CommonConst.TAttributeExtProperties.IsEnableMasking;
        private const string IsEnableColumnPermission = CommonConst.TAttributeExtProperties.IsEnableColumnPermission;

        public TSchema BuildSchema()
        {
            TSchema schema = new TSchema();
            schema.ActionID = this.ID;
            schema.ActionCode = this.Code;
            schema.ActionName = this.Name;
            schema.MetadataType = TEntityType.DQ;
            schema.ResultType = DataType.List;
            if (this.IsBigDataQuerySource())
            { 
                // Todo:
                //schema.Entity = BuildTEntityForBigDataSource(this); 
            }
            else
                schema.Entity = BuildTEntity(this);
            return schema;
        }

        public TSchema BuildFlatSchema()
        {
            TSchema schema = new TSchema();
            schema.ActionID = this.ID;
            schema.ActionCode = this.Code;
            schema.ActionName = this.Name;
            schema.MetadataType = TEntityType.DQ;
            schema.ResultType = DataType.List;
            if (this.IsBigDataQuerySource())
            {
                // Todo:
                //schema.Entity = BuildTEntityForBigDataSource(this);
            }
            else
                schema.Entity = BuildFlatTEntity(this);
            return schema;
        }

        public override IRefSchemaEntity BuildRefSchema()
        {
            try
            {
                var dq = this;
                DataQueryRefSchemaEntity dqSchema = new DataQueryRefSchemaEntity
                {
                    ID = dq.MetaDataID,
                    Code = dq.MetaDataCode,
                    Name = dq.MetaDataName,
                    Sources = new Dictionary<string, DQSource>(),
                    __AggreAndGroupColumns = new Dictionary<string, DQColumn>(),
                    __UserDefineColumns = new Dictionary<string, DQColumn>(),
                    SubDQ = new Dictionary<string, DQSub>(),
                    Param = new Dictionary<string, DQParam>()
                };
                foreach (var source in dq.DataQuerySources)
                {
                    dqSchema.Sources[source.Alias] = DQSource.Mapping(dq, source);
                }
                var aggAndGroupColumn = dq.DataQueryColumns.Where(col => col.ColumnType == ColumnType.Aggregate || col.ColumnType == ColumnType.Group).ToList();
                if (aggAndGroupColumn != null)
                {
                    aggAndGroupColumn.ForEach(c => {
                        dqSchema.__AggreAndGroupColumns[c.Alias] = DQColumn.Mapping(dq, c);
                    });
                }
                var userDefinedColumn = dq.DataQueryColumns.Where(col => col.ColumnType == ColumnType.Express).ToList();
                if (userDefinedColumn != null)
                {
                    userDefinedColumn.ForEach(c => {
                        dqSchema.__UserDefineColumns[c.Alias] = DQColumn.Mapping(dq, c);
                    });
                }
                if (dq.DataQueryParams != null)
                {
                    foreach (var par in dq.DataQueryParams.Where(p => p.IsInputParam))
                    {
                        dqSchema.Param[par.Code] = DQParam.Mapping(dq, par);
                    }
                }
                if (dq.SubQuerys != null)
                {
                    foreach (var sub in dq.SubQuerys)
                    {
                        dqSchema.SubDQ[sub.SubQueryAlias] = DQSub.Mapping(dq, sub);
                    }
                }
                return dqSchema;
            }
            catch (Exception e)
            {
                throw new Exception($"DQ:{Code}构造RefSchema失败, msg:{e.Message}, e:{e}", e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        private TEntity BuildTEntity(DataQuery dataQuery, 
                                     DataQuery parentQuery = null, 
                                     DataQuerySubQuery subQueryMeta = null, 
                                     int depth = 0, 
                                     HashSet<string> dqSchemaCache = null,
                                     string parentRefSchemaExpr = null)
        {
            try
            {
                if (dqSchemaCache == null)
                    dqSchemaCache = new HashSet<string>();
                var entity = new TEntity(TEntityType.DQ)
                {
                    MetadataID = dataQuery.ID,
                    MetadataCode = dataQuery.Code,
                    MetadataName = dataQuery.Name,
                    MetadataType = TEntityType.DQ,
                    ResultType = DataType.List,
                };
                if (depth <= 0)
                {
                    entity.RefSchemaExpr = $"{RefSchemaPrefix}.{dataQuery.Code}";
                }
                else
                {
                    entity.RefSchemaExpr = $"{RefSchemaPrefix}.{dataQuery.Code}";   //在引用路径表达式中没有元数据间的嵌套，全部由Schema.DQ开始
                                                                                    //entity.RefSchemaExpr = $"{parentRefSchemaExpr}.{dataQuery.Code}";
                }
                if (subQueryMeta != null)    //当存在子查询时，配置Relation关联关系
                {
                    entity.Relation = new TEntityRelation
                    {
                        ID = "",
                        FromTEntityCode = parentQuery.Code,
                        FromTAttributeCode = parentQuery.DataQueryColumns.FirstOrDefault(col => col.ID == subQueryMeta.MainQueryColumnID)?.Alias,
                        ToTEntityCode = subQueryMeta.SubQueryAlias,
                        ToTAttributeCode = dataQuery.DataQueryColumns.FirstOrDefault(col => col.ID == subQueryMeta.SubQueryColumnID)?.Alias,
                    };
                }

                entity.Attributes = new List<TAttribute>();
                var aggregateCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false && (x.ColumnType == ColumnType.Aggregate || x.ColumnType == ColumnType.Group)).OrderBy(x => x.Sort).ToList();
                var normalCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false).OrderBy(x => x.Sort).ToList();

                List<DataQueryColumn> resultCols = null;

                //处理聚合列，如果包含分组&集合列，不处理普通列
                if (aggregateCols != null && aggregateCols.Count > 0)
                {
                    resultCols = aggregateCols;

                    foreach (DataQueryColumn aggNGroupColumn in resultCols)
                    {
                        TAttribute aggNGroupColumnAttr = new TAttribute
                        {
                            ID = aggNGroupColumn.Alias,
                            Code = aggNGroupColumn.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{AggAndGroupColumnNameSpace}.{aggNGroupColumn.Alias}",
                            DataType = ConvertAggregateType(aggNGroupColumn.AggregateType),
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = aggNGroupColumn.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = aggNGroupColumn.Sort,
                            ExtProperties = new Dictionary<string, object>(),
                        };
                        if (aggNGroupColumn.TryGetDataColumnHelpSetting(dataQuery, out DataObjectColumnHelpSetting setting))
                        {
                            aggNGroupColumnAttr.ExtProperties[nameof(DataObjectColumnHelpSetting)] = setting;
                        }
                        entity.AddAttribute(aggNGroupColumnAttr);
                    }
                }
                else
                {
                    //非隐藏列集合
                    resultCols = normalCols;

                    //非普通列
                    var expressColumns = resultCols.Where(x => x.ColumnType != ColumnType.Normal).ToList();

                    foreach (var item in expressColumns)
                    {
                        TAttribute expressColumnAttr = new TAttribute
                        {
                            ID = item.Alias,
                            Code = item.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{ExprColumnNameSpace}.{item.Alias}",   //用户自定义列放到特殊集合下
                            DataType = ConvertDataType(item.ColumnDataType, item),
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = item.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = item.Sort,
                            ExtProperties = null,
                        };
                        entity.AddAttribute(expressColumnAttr);
                    }

                    //普通列按DO.ID分组
                    var normalColsGroupByDQSourceID = normalCols.Where(x => x.ColumnType == ColumnType.Normal).GroupBy(x => x.DataQuerySourceID).ToList();
                    foreach (var normalColsGroup in normalColsGroupByDQSourceID)
                    {
                        var normalColumns = normalColsGroup.ToList();
                        //按DO分组处理，每个DO节点下包含一堆列
                        if (normalColumns != null && normalColumns.Count > 0)
                        {
                            DataQuerySource dataQuerySource = dataQuery.DataQuerySources.FirstOrDefault(t => t.ID == normalColsGroup.Key);
                            if (dataQuerySource == null)
                            {
                                throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的不存在SourceID:{normalColsGroup.Key}，请检查");
                            }
                            DataObject dataObject = dataQuerySource.DataObject;

                            if (dataObject == null)
                            {
                                throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的DO:{normalColumns[0].DataObjectID}获取实例失败，请检查");
                            }
                            TAttribute doNode = new TAttribute
                            {
                                ID = dataObject.ID,
                                Code = dataQuerySource.Alias,
                                RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataQuerySource.Alias}",
                                DataType = DataType.Record,
                                EntityType = TEntityType.DO,
                                IsDetail = false,
                                IsPrimaryKey = false,
                                Name = dataObject.Name,
                                MetadataCode = dataQuery.Code,
                                Entity = new TEntity(TEntityType.Attribute)
                                {
                                    MetadataID = dataObject.ID,
                                    MetadataCode = dataObject.Code,
                                    MetadataName = dataObject.Name,
                                    RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataObject.Code}",
                                    MetadataType = TEntityType.DO,
                                    ResultType = DataType.Record,
                                },
                            };
                            doNode.Entity.Attributes = new List<TAttribute>();

                            //增加DO节点
                            entity.AddAttribute(doNode);

                            //增加DO下的子节点
                            foreach (DataQueryColumn normalColumn in normalColumns)
                            {
                                try
                                {
                                    TAttribute normalColumnAttr = new TAttribute
                                    {
                                        ID = normalColumn.Alias,
                                        Code = normalColumn.Alias,
                                        Name = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : normalColumn.Alias,
                                        RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataQuerySource.Alias}.{Columns}.{normalColumn.Alias}",
                                        DataType = ConvertDataType(normalColumn.ColumnDataType, normalColumn),
                                        Length = normalColumn.DataColumn == null ? 0 : normalColumn.DataColumn.Length,
                                        Precision = normalColumn.DataColumn == null ? 0 : normalColumn.DataColumn.Precision,
                                        IsRequired = normalColumn.DataColumn == null ? false : !normalColumn.DataColumn.IsNullable,
                                        DefaultValue = null,    //DQ列不应有默认值
                                        EntityType = TEntityType.Attribute,
                                        IsDetail = true,
                                        IsPrimaryKey = normalColumn.DataColumn == null ? false : normalColumn.DataColumn.IsPkColumn,
                                        SourceColumnID = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DataColumn?.ID : "",
                                        SourceColumnCode = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DataColumn?.ColumnName : "",
                                        SourceColumnName = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : "",
                                        MetadataCode = dataQuery.Code,
                                        SortOrder = normalColumn.Sort,
                                        ExtProperties = new Dictionary<string, object>(),
                                    };
                                    if (normalColumn.DataColumn != null)
                                    {
                                        var col = normalColumn.DataColumn;
                                        if (col.IsFkColumn)
                                        {
                                            normalColumnAttr.AttributeType = TAttributeType.ForeignKey;
                                            if (col.IsRefDataObject)
                                            {
                                                normalColumnAttr.ExtProperties[IsSDO] = false;
                                                normalColumnAttr.ExtProperties[IsStateField] = false;
                                            }
                                            else
                                            {
                                                normalColumnAttr.ExtProperties[SDOID] = col.RelatedDataObjectID;
                                                normalColumnAttr.ExtProperties[IsSDO] = true;
                                            }
                                        }
                                        else
                                        {
                                            normalColumnAttr.AttributeType = TAttributeType.Normal;
                                        }
                                    }
                                    if (normalColumn.TryGetDataColumnHelpSetting(dataQuery, out DataObjectColumnHelpSetting setting))
                                    {
                                        normalColumnAttr.ExtProperties[nameof(DataObjectColumnHelpSetting)] = setting;
                                    }
                                    if (normalColumn.DataColumn != null)
                                    {
                                        normalColumnAttr.ExtProperties[IsInternational] = normalColumn.DataColumn.IsInternational;
                                        normalColumnAttr.ExtProperties[IsEnableMasking] = normalColumn.DataColumn.MaskingRule.IsEnable;
                                        normalColumnAttr.ExtProperties[MaskRule] = normalColumn.DataColumn.MaskingRule;
                                        normalColumnAttr.ExtProperties[IsEnableColumnPermission] = normalColumn.DataColumn.IsEnableColumnPermission;
                                    }

                                    doNode.Entity.AddAttribute(normalColumnAttr);
                                    //增加国际化列处理
                                    if (normalColumn.DataColumn != null && normalColumn.DataColumn.IsInternational)
                                    {
                                        var mapping = InternationalDataTools.LanguageMapping;
                                        if (mapping.Count > 0)
                                        {
                                            foreach (var langKey in mapping.Keys)
                                            {
                                                string logicTableFieldName = InternationalTools.GetLogicFieldName(normalColumn.Alias, mapping[langKey]);
                                                TAttribute i18NAttr = normalColumnAttr.CloneAttr();
                                                i18NAttr.Code = logicTableFieldName;
                                                i18NAttr.Name += InternationalTools.GetLogicFieldNameSuffix(mapping[langKey]);
                                                i18NAttr.ExtProperties[IsParalanguage] = true;
                                                doNode.Entity.AddAttribute(i18NAttr);
                                            }
                                        }
                                        try
                                        {
                                            //将主语言拼接I18N Code返回，例如Main: Name_en_US，以兼容下拉帮助缓存的国际化
                                            var mainLanguage = LanguageService.GetSupportLanguages()?.FirstOrDefault(l => l.IsMainLanguage);
                                            if (mainLanguage != null)
                                            {
                                                string logicFieldName = InternationalTools.GetLogicFieldName(normalColumn.Alias, mainLanguage.ID);
                                                TAttribute mainLangI18NAttr = normalColumnAttr.CloneAttr();
                                                mainLangI18NAttr.Code = logicFieldName;
                                                mainLangI18NAttr.Name += InternationalTools.GetLogicFieldNameSuffix(mainLanguage.ID);
                                                mainLangI18NAttr.ExtProperties[IsParalanguage] = true;
                                                doNode.Entity.AddAttribute(mainLangI18NAttr);
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                        }
                                    }

                                    //处理掩码&权限
                                    if (normalColumn.DataColumn != null && normalColumn.DataColumn.MaskingRule.IsEnable)
                                    {
                                        TAttribute maskAttr = normalColumnAttr.CloneAttr();
                                        maskAttr.Code = DataColumn.GetMaskColumnName(dataObject, normalColumn.Alias);
                                        maskAttr.Name += normalColumn.DisplayName + "掩码";
                                        maskAttr.ExtProperties[IsMaskingColumn] = true;
                                        maskAttr.ExtProperties[OriginMaskingColumn] = normalColumn.Alias;
                                        maskAttr.ExtProperties[MaskRule] = normalColumn.DataColumn.MaskingRule;
                                        entity.Attributes.Add(maskAttr);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的列:{normalColumn?.ID}生成TAttribute失败，请检查列信息。msg:{e.Message}", e);
                                }
                            }
                        }
                    }
                    if (dataQuery.SubQuerys != null && dataQuery.SubQuerys.Count > 0)
                    {
                        foreach (var sub in dataQuery.SubQuerys)
                        {
                            //var subQueryCol = sub.SubQuery.DataQueryColumns.FirstOrDefault(col => col.ID == sub.SubQueryColumnID);
                            //var subQueryColDataObjectID = subQueryCol.DataObject.ID;
                            ////通过子查询元数据中子查询列对应的DataObjetID找到设置子Schema的地方
                            //var SubAttr = Entity.Attributes.FirstOrDefault(attr => attr.ID == subQueryColDataObjectID);

                            if (dqSchemaCache.Contains(sub.ID)) continue;   //跳过已执行过的SubQuery
                            else dqSchemaCache.Add(sub.ID);

                            var mainQueryColumn = dataQuery.DataQueryColumns?.FirstOrDefault(col => col.ID == sub.MainQueryColumnID);
                            var attr = new TAttribute
                            {
                                ID = sub.SubQuery.ID,
                                Code = sub.SubQueryAlias,
                                RefSchemaExpr = $"{entity.RefSchemaExpr}.{SubDQ}.{sub.SubQueryAlias}",
                                MetadataCode = sub.SubQuery.Code,
                                DataType = DataType.List,
                                EntityType = TEntityType.DQ,
                                IsDetail = false,
                                IsPrimaryKey = false,
                                Name = sub.SubQuery.Name
                            };
                            attr.Entity = BuildTEntity(sub.SubQuery, dataQuery, sub, depth + 1, dqSchemaCache, entity.RefSchemaExpr);
                            //增加DO节点
                            entity.AddAttribute(attr);
                        }
                    }
                }

                return entity;
            }
            catch (Exception e)
            {
                throw new Exception($"DQ:{dataQuery?.Code} BuildSchema失败，errMsg:{e.Message}，stackTrace:{e.StackTrace}", e);
            }
        }


        /// <summary>
        /// 获取拉平的Entity结构
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        private TEntity BuildFlatTEntity(DataQuery dataQuery,
                                     DataQuery parentQuery = null,
                                     DataQuerySubQuery subQueryMeta = null,
                                     int depth = 0,
                                     HashSet<string> dqSchemaCache = null,
                                     string parentRefSchemaExpr = null)
        {
            try
            {
                if (dqSchemaCache == null)
                    dqSchemaCache = new HashSet<string>();
                var entity = new TEntity(TEntityType.DQ)
                {
                    MetadataID = dataQuery.ID,
                    MetadataCode = dataQuery.Code,
                    MetadataName = dataQuery.Name,
                    MetadataType = TEntityType.DQ,
                    ResultType = DataType.List,
                };
                if (depth <= 0)
                {
                    entity.RefSchemaExpr = $"{RefSchemaPrefix}.{dataQuery.Code}";
                }
                else
                {
                    entity.RefSchemaExpr = $"{RefSchemaPrefix}.{dataQuery.Code}";   //在引用路径表达式中没有元数据间的嵌套，全部由Schema.DQ开始
                                                                                    //entity.RefSchemaExpr = $"{parentRefSchemaExpr}.{dataQuery.Code}";
                }
                if (subQueryMeta != null)    //当存在子查询时，配置Relation关联关系
                {
                    entity.Relation = new TEntityRelation
                    {
                        ID = "",
                        FromTEntityCode = parentQuery.Code,
                        FromTAttributeCode = parentQuery.DataQueryColumns.FirstOrDefault(col => col.ID == subQueryMeta.MainQueryColumnID)?.Alias,
                        ToTEntityCode = subQueryMeta.SubQueryAlias,
                        ToTAttributeCode = dataQuery.DataQueryColumns.FirstOrDefault(col => col.ID == subQueryMeta.SubQueryColumnID)?.Alias,
                    };
                }

                entity.Attributes = new List<TAttribute>();
                var aggregateCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false && (x.ColumnType == ColumnType.Aggregate || x.ColumnType == ColumnType.Group)).OrderBy(x => x.Sort).ToList();
                var normalCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false).OrderBy(x => x.Sort).ToList();

                List<DataQueryColumn> resultCols = null;

                //处理聚合列，如果包含分组&集合列，不处理普通列
                if (aggregateCols != null && aggregateCols.Count > 0)
                {
                    resultCols = aggregateCols;

                    foreach (DataQueryColumn aggNGroupColumn in resultCols)
                    {
                        TAttribute aggNGroupColumnAttr = new TAttribute
                        {
                            ID = aggNGroupColumn.Alias,
                            Code = aggNGroupColumn.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{AggAndGroupColumnNameSpace}.{aggNGroupColumn.Alias}",
                            DataType = ConvertAggregateType(aggNGroupColumn.AggregateType),
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = aggNGroupColumn.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = aggNGroupColumn.Sort,
                            ExtProperties = new Dictionary<string, object>(),
                        };
                        if (aggNGroupColumn.TryGetDataColumnHelpSetting(dataQuery, out DataObjectColumnHelpSetting setting))
                        {
                            aggNGroupColumnAttr.ExtProperties[nameof(DataObjectColumnHelpSetting)] = setting;
                        }
                        entity.AddAttribute(aggNGroupColumnAttr);
                    }
                }
                else
                {
                    //非隐藏列集合
                    resultCols = normalCols;

                    //非普通列
                    var expressColumns = resultCols.Where(x => x.ColumnType != ColumnType.Normal).ToList();

                    foreach (var item in expressColumns)
                    {
                        TAttribute expressColumnAttr = new TAttribute
                        {
                            ID = item.Alias,
                            Code = item.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{ExprColumnNameSpace}.{item.Alias}",   //用户自定义列放到特殊集合下
                            DataType = ConvertDataType(item.ColumnDataType, item),
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = item.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = item.Sort,
                            ExtProperties = null,
                        };
                        entity.AddAttribute(expressColumnAttr);
                    }

                    //普通列按DO.ID分组
                    var normalColsGroupByDQSourceID = normalCols.Where(x => x.ColumnType == ColumnType.Normal).GroupBy(x => x.DataQuerySourceID).ToList();
                    foreach (var normalColsGroup in normalColsGroupByDQSourceID)
                    {
                        var normalColumns = normalColsGroup.ToList();
                        //按DO分组处理，每个DO节点下包含一堆列
                        if (normalColumns != null && normalColumns.Count > 0)
                        {
                            DataQuerySource dataQuerySource = dataQuery.DataQuerySources.FirstOrDefault(t => t.ID == normalColsGroup.Key);
                            DataObject dataObject = dataQuerySource.DataObject;

                            if (dataObject == null)
                            {
                                throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的DO:{normalColumns[0].DataObjectID}获取实例失败，请检查");
                            }

                            //增加DO下的子节点
                            foreach (DataQueryColumn normalColumn in normalColumns)
                            {
                                try
                                {
                                    TAttribute normalColumnAttr = new TAttribute
                                    {
                                        ID = normalColumn.Alias,
                                        Code = normalColumn.Alias,
                                        Name = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : normalColumn.Alias,
                                        RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataQuerySource.Alias}.{Columns}.{normalColumn.Alias}",
                                        DataType = ConvertDataType(normalColumn.ColumnDataType, normalColumn),
                                        Length = normalColumn.DataColumn == null ? 0 : normalColumn.DataColumn.Length,
                                        Precision = normalColumn.DataColumn == null ? 0 : normalColumn.DataColumn.Precision,
                                        IsRequired = normalColumn.DataColumn == null ? false : !normalColumn.DataColumn.IsNullable,
                                        DefaultValue = null,    //DQ列不应有默认值
                                        EntityType = TEntityType.Attribute,
                                        IsDetail = true,
                                        IsPrimaryKey = normalColumn.DataColumn == null ? false : normalColumn.DataColumn.IsPkColumn,
                                        SourceColumnID = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DataColumn.ID : "",
                                        SourceColumnCode = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DataColumn.ColumnName : "",
                                        SourceColumnName = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : "",
                                        MetadataCode = dataQuery.Code,
                                        SortOrder = normalColumn.Sort,
                                        ExtProperties = new Dictionary<string, object>(),
                                    };
                                    if (normalColumn.DataColumn != null)
                                    {
                                        var col = normalColumn.DataColumn;
                                        if (col.IsFkColumn)
                                        {
                                            normalColumnAttr.AttributeType = TAttributeType.ForeignKey;
                                            if (col.IsRefDataObject)
                                            {
                                                normalColumnAttr.ExtProperties[IsSDO] = false;
                                                normalColumnAttr.ExtProperties[IsStateField] = false;
                                            }
                                            else
                                            {
                                                normalColumnAttr.ExtProperties[SDOID] = col.RelatedDataObjectID;
                                                normalColumnAttr.ExtProperties[IsSDO] = true;
                                            }
                                        }
                                        else
                                        {
                                            normalColumnAttr.AttributeType = TAttributeType.Normal;
                                        }
                                    }
                                    if (normalColumn.TryGetDataColumnHelpSetting(dataQuery, out DataObjectColumnHelpSetting setting))
                                    {
                                        normalColumnAttr.ExtProperties[nameof(DataObjectColumnHelpSetting)] = setting;
                                    }
                                    normalColumnAttr.ExtProperties[IsInternational] = normalColumn.DataColumn.IsInternational;
                                    normalColumnAttr.ExtProperties[IsEnableMasking] = normalColumn.DataColumn.MaskingRule.IsEnable;
                                    normalColumnAttr.ExtProperties[MaskRule] = normalColumn.DataColumn.MaskingRule;
                                    normalColumnAttr.ExtProperties[IsEnableColumnPermission] = normalColumn.DataColumn.IsEnableColumnPermission;

                                    entity.AddAttribute(normalColumnAttr);
                                    //增加国际化列处理
                                    if (normalColumn.DataColumn != null && normalColumn.DataColumn.IsInternational)
                                    {
                                        var mapping = InternationalDataTools.LanguageMapping;
                                        if (mapping.Count > 0)
                                        {
                                            foreach (var langKey in mapping.Keys)
                                            {
                                                string logicTableFieldName = InternationalTools.GetLogicFieldName(normalColumn.Alias, mapping[langKey]);
                                                TAttribute i18NAttr = normalColumnAttr.CloneAttr();
                                                i18NAttr.Code = logicTableFieldName;
                                                i18NAttr.Name += InternationalTools.GetLogicFieldNameSuffix(mapping[langKey]);
                                                i18NAttr.ExtProperties[IsParalanguage] = true;
                                                entity.AddAttribute(normalColumnAttr);
                                            }
                                        }
                                        try
                                        {
                                            //将主语言拼接I18N Code返回，例如Main: Name_en_US，以兼容下拉帮助缓存的国际化
                                            var mainLanguage = LanguageService.GetSupportLanguages()?.FirstOrDefault(l => l.IsMainLanguage);
                                            if (mainLanguage != null)
                                            {
                                                string logicFieldName = InternationalTools.GetLogicFieldName(normalColumn.Alias, mainLanguage.ID);
                                                TAttribute mainLangI18NAttr = normalColumnAttr.CloneAttr();
                                                mainLangI18NAttr.Code = logicFieldName;
                                                mainLangI18NAttr.Name += InternationalTools.GetLogicFieldNameSuffix(mainLanguage.ID);
                                                mainLangI18NAttr.ExtProperties[IsParalanguage] = true;
                                                entity.AddAttribute(normalColumnAttr);
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                        }
                                    }

                                    //处理掩码&权限
                                    if (normalColumn.DataColumn.MaskingRule.IsEnable)
                                    {
                                        TAttribute maskAttr = normalColumnAttr.CloneAttr();
                                        maskAttr.Code = DataColumn.GetMaskColumnName(dataObject, normalColumn.Alias);
                                        maskAttr.Name += normalColumn.DisplayName + "掩码";
                                        maskAttr.ExtProperties[IsMaskingColumn] = true;
                                        maskAttr.ExtProperties[OriginMaskingColumn] = normalColumn.Alias;
                                        maskAttr.ExtProperties[MaskRule] = normalColumn.DataColumn.MaskingRule;
                                        entity.Attributes.Add(maskAttr);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的列:{normalColumn?.ID}生成TAttribute失败，请检查列信息。msg:{e.Message}", e);
                                }
                            }
                        }
                    }
                    if (dataQuery.SubQuerys != null && dataQuery.SubQuerys.Count > 0)
                    {
                        foreach (var sub in dataQuery.SubQuerys)
                        {
                            //var subQueryCol = sub.SubQuery.DataQueryColumns.FirstOrDefault(col => col.ID == sub.SubQueryColumnID);
                            //var subQueryColDataObjectID = subQueryCol.DataObject.ID;
                            ////通过子查询元数据中子查询列对应的DataObjetID找到设置子Schema的地方
                            //var SubAttr = Entity.Attributes.FirstOrDefault(attr => attr.ID == subQueryColDataObjectID);

                            if (dqSchemaCache.Contains(sub.ID)) continue;   //跳过已执行过的SubQuery
                            else dqSchemaCache.Add(sub.ID);
                            if (sub.SubQuery == null) continue;

                            var mainQueryColumn = dataQuery.DataQueryColumns?.FirstOrDefault(col => col.ID == sub.MainQueryColumnID);
                            var attr = new TAttribute
                            {
                                ID = sub.SubQuery.ID,
                                Code = sub.SubQueryAlias,
                                RefSchemaExpr = $"{entity.RefSchemaExpr}.{SubDQ}.{sub.SubQueryAlias}",
                                MetadataCode = sub.SubQuery.Code,
                                DataType = DataType.List,
                                EntityType = TEntityType.DQ,
                                IsDetail = false,
                                IsPrimaryKey = false,
                                Name = sub.SubQuery.Name,
                                ExtProperties = new Dictionary<string, object>(),
                            };
                            attr.OriginDataType = sub.SubQuery.Code;
                            attr.ExtProperties["RefMetaType"] = DataModelConst.DQMetaType;
                            attr.Entity = BuildFlatTEntity(sub.SubQuery, dataQuery, sub, depth + 1, dqSchemaCache, entity.RefSchemaExpr);
                            //增加DO节点
                            entity.AddAttribute(attr);
                        }
                    }
                }

                return entity;
            }
            catch (Exception e)
            {
                throw new Exception($"DQ:{dataQuery?.Code} BuildFlatSchema失败，errMsg:{e.Message}，stackTrace:{e.StackTrace}", e);
            }
        }

        /// <summary>
        /// 大数据DQ的BuildSchema
        /// </summary>
        /// <param name="dataQuery"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        /* ToDo:
        private TEntity BuildTEntityForBigDataSource(DataQuery dataQuery,
                                     HashSet<string> dqSchemaCache = null,
                                     string parentRefSchemaExpr = null)
        {
            try
            {
                if (dqSchemaCache == null)
                    dqSchemaCache = new HashSet<string>();
                var entity = new TEntity(TEntityType.DQ)
                {
                    MetadataID = dataQuery.ID,
                    MetadataCode = dataQuery.Code,
                    MetadataName = dataQuery.Name,
                    MetadataType = TEntityType.DQ,
                    ResultType = DataType.List,
                };
                entity.RefSchemaExpr = $"{RefSchemaPrefix}.{dataQuery.Code}";
               
                entity.Attributes = new List<TAttribute>();
                var aggregateCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false && (x.ColumnType == ColumnType.Aggregate || x.ColumnType == ColumnType.Group)).OrderBy(x => x.Sort).ToList();
                var normalCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false).OrderBy(x => x.Sort).ToList();
                var userDefinedCols = dataQuery.DataQueryColumns.Where(x => x.IsHide == false && (x.ColumnType == ColumnType.Express))?.OrderBy(x => x.Sort).ToList();

                List<DataQueryColumn> resultCols = null;

                //处理聚合列，如果包含分组&集合列，不处理普通列
                if (aggregateCols != null && aggregateCols.Count > 0)
                {
                    resultCols = aggregateCols;
                    if (userDefinedCols != null && userDefinedCols.Count > 0)
                        resultCols?.AddRange(userDefinedCols);

                    foreach (DataQueryColumn aggNGroupColumn in resultCols)
                    {
                        TAttribute aggNGroupColumnAttr = new TAttribute
                        {
                            ID = aggNGroupColumn.Alias,
                            Code = aggNGroupColumn.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{AggAndGroupColumnNameSpace}.{aggNGroupColumn.Alias}",
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = aggNGroupColumn.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = aggNGroupColumn.Sort,
                            ExtProperties = new Dictionary<string, object>(),
                        };
                        if (aggNGroupColumn.ColumnType == ColumnType.Express)
                            aggNGroupColumnAttr.DataType = DataType.String;
                        else
                            aggNGroupColumnAttr.DataType = ConvertAggregateType(aggNGroupColumn.AggregateType);
                        //if (aggNGroupColumn.TryGetDataColumnHelpSetting(dataQuery, out DataObjectColumnHelpSetting setting))
                        //{
                        //    aggNGroupColumnAttr.ExtProperties[nameof(DataObjectColumnHelpSetting)] = setting;
                        //}
                        entity.AddAttribute(aggNGroupColumnAttr);
                    }
                }
                else
                {
                    //非隐藏列集合
                    resultCols = normalCols;

                    //非普通列
                    var expressColumns = resultCols.Where(x => x.ColumnType != ColumnType.Normal).ToList();

                    foreach (var item in expressColumns)
                    {
                        TAttribute expressColumnAttr = new TAttribute
                        {
                            ID = item.Alias,
                            Code = item.Alias,
                            RefSchemaExpr = $"{entity.RefSchemaExpr}.{ExprColumnNameSpace}.{item.Alias}",   //用户自定义列放到特殊集合下
                            DataType = ConvertDataType(item.ColumnDataType, item),
                            EntityType = TEntityType.Attribute,
                            IsDetail = true,
                            IsPrimaryKey = false,
                            Name = item.DisplayName,
                            MetadataCode = dataQuery.Code,
                            SortOrder = item.Sort,
                            ExtProperties = null,
                        };
                        entity.AddAttribute(expressColumnAttr);
                    }

                    //普通列按DO.ID分组
                    var normalColsGroupByDQSourceID = normalCols.Where(x => x.ColumnType == ColumnType.Normal).GroupBy(x => x.DataQuerySourceID).ToList();
                    foreach (var normalColsGroup in normalColsGroupByDQSourceID)
                    {
                        var normalColumns = normalColsGroup.ToList();
                        //按DO分组处理，每个DO节点下包含一堆列
                        if (normalColumns != null && normalColumns.Count > 0)
                        {
                            DataQuerySource dataQuerySource = dataQuery.DataQuerySources.FirstOrDefault(t => t.ID == normalColsGroup.Key);
                            //DataAsset dataAsset = dataQuery.DataQuerySources.FirstOrDefault(s => s.IsMainSource)?.DataAsset;
                            DataAsset dataAsset = dataQuerySource.DataAsset;
                            if (dataAsset == null)
                            {
                                throw new FasException(DataModelErrorCode.DQ.BuildSchemaError, $"Get DQ:{dataQuery?.Code} Source's DataAsset:{dataQuerySource?.DataObjectID} failed");
                            } 

                            TAttribute doNode = new TAttribute
                            {
                                ID = dataAsset.ID,
                                Code = dataQuerySource.Alias,
                                RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataQuerySource.Alias}",
                                DataType = DataType.Record,
                                EntityType = TEntityType.DO,
                                IsDetail = false,
                                IsPrimaryKey = false,
                                Name = dataAsset.Name,
                                MetadataCode = dataQuery.Code,
                                Entity = new TEntity(TEntityType.Attribute)
                                {
                                    MetadataID = dataAsset.ID,
                                    MetadataCode = dataAsset.Code,
                                    MetadataName = dataAsset.Name,
                                    RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataAsset.Code}",
                                    MetadataType = TEntityType.DO,
                                    ResultType = DataType.Record,
                                },
                            };
                            doNode.Entity.Attributes = new List<TAttribute>();

                            //增加DO节点
                            entity.AddAttribute(doNode);

                            //增加DO下的子节点
                            foreach (DataQueryColumn normalColumn in normalColumns)
                            {
                                try
                                {
                                    BigDataColumn bigDataColumn = dataAsset.Columns.FirstOrDefault(c => c.ID == normalColumn.DataObjectColumnID);
                                    TAttribute normalColumnAttr = new TAttribute
                                    {
                                        ID = normalColumn.Alias,
                                        Code = normalColumn.Alias,
                                        Name = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : normalColumn.Alias,
                                        RefSchemaExpr = $"{entity.RefSchemaExpr}.{Sources}.{dataQuerySource.Alias}.{Columns}.{normalColumn.Alias}",
                                        DataType = ConvertDataType(normalColumn.ColumnDataType, normalColumn),
                                        Length = bigDataColumn?.Length.Value == null ? 0 : bigDataColumn.Length.Value,
                                        Precision = bigDataColumn == null ? 0 : bigDataColumn.Precision,
                                        IsRequired = bigDataColumn == null ? false : !bigDataColumn.IsNullable,
                                        DefaultValue = null,    //DQ列不应有默认值
                                        EntityType = TEntityType.Attribute,
                                        IsDetail = true,
                                        IsPrimaryKey = bigDataColumn == null ? false : bigDataColumn.IsPkColumn,
                                        SourceColumnID = normalColumn.ColumnType == ColumnType.Normal ? bigDataColumn.ID : "",
                                        SourceColumnCode = normalColumn.ColumnType == ColumnType.Normal ? bigDataColumn.ColumnName : "",
                                        SourceColumnName = normalColumn.ColumnType == ColumnType.Normal ? normalColumn.DisplayName : "",
                                        MetadataCode = dataQuery.Code,
                                        SortOrder = normalColumn.Sort,
                                        ExtProperties = new Dictionary<string, object>(),
                                    };

                                    if (bigDataColumn != null)
                                    {
                                        normalColumnAttr.ExtProperties[IsEnableMasking] = bigDataColumn.MaskingRule.IsEnable;
                                        normalColumnAttr.ExtProperties[MaskRule] = bigDataColumn.MaskingRule;
                                        normalColumnAttr.ExtProperties[IsEnableColumnPermission] = bigDataColumn.IsEnableColumnPermission;
                                    }

                                    doNode.Entity.AddAttribute(normalColumnAttr);

                                    //处理掩码&权限
                                    if (bigDataColumn != null && bigDataColumn.MaskingRule.IsEnable)
                                    {
                                        TAttribute maskAttr = normalColumnAttr.CloneAttr();
                                        maskAttr.Code = BigDataColumn.GetMaskColumnName(dataAsset, normalColumn.Alias);
                                        maskAttr.Name += normalColumn.DisplayName + "掩码";
                                        maskAttr.ExtProperties[IsMaskingColumn] = true;
                                        maskAttr.ExtProperties[OriginMaskingColumn] = normalColumn.Alias;
                                        maskAttr.ExtProperties[MaskRule] = bigDataColumn.MaskingRule;
                                        entity.Attributes.Add(maskAttr);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new FasException(DataModelErrorCode.DQ.BuildSchemaError,
                                        $"大数据DQ id:{dataQuery.ID},Code:{dataQuery?.Code}的列:{normalColumn?.ID}生成TAttribute失败，请检查列信息。msg:{e.Message}", e);
                                }
                            }
                        }
                    }
                }

                return entity;
            }
            catch (Exception e)
            {
                throw new Exception($"DQ:{dataQuery?.Code} BuildSchema失败，errMsg:{e.Message}，stackTrace:{e.StackTrace}", e);
            }
        }
        */

        #region Funcs
        /// <summary>
        /// 处理DQ的DataQueryColumn指向的DataColumn实际是个外键列的情况，获取指向的外键关联DO的主键数据类型
        /// </summary>
        /// <param name="type"></param>
        /// <param name="dataQueryColumn"></param>
        /// <returns></returns>
        private static DataType ConvertDataType(string type, DataQueryColumn dataQueryColumn)
        {
            try
            {
                switch (type.ToLower())
                {
                    case "binary":
                        return DataType.Binary;
                    case "boolean":
                        return DataType.Boolean;
                    case "int":
                        return DataType.Int;
                    case "long":
                        return DataType.Long;
                    case "decimal":
                        return DataType.Decimal;
                    case "datetime":
                        return DataType.DateTime;
                    case "timestamp":
                        return DataType.Timestamp;
                    case "date":
                        return DataType.Date;
                    case "time":
                        return DataType.Time;
                    case "string":
                        return DataType.String;
                    case "record":
                        return DataType.Record;
                    case "list":
                        return DataType.List;
                    default:
                        if (dataQueryColumn?.DataColumn?.RelatedDataObjectPrimaryKey?.ApplicationDataType != null)
                        {
                            var dataType = dataQueryColumn.DataColumn.RelatedDataObjectPrimaryKey.ApplicationDataType;
                            return DataTypeUtil.ConvertToDataType(dataType);
                        }
                        return DataType.String;
                }

            }
            catch (Exception e)
            {
                throw new FasException(DataModelErrorCode.DataType.TypeCastError, $"DQ类型转换失败，类型:{type}，");
            }
        }

        private static DataType ConvertAggregateType(AggregateType aggregateType)
        {
            switch (aggregateType)
            {
                case AggregateType.COUNT:
                case AggregateType.SUM:
                case AggregateType.AVG:
                case AggregateType.MAX:
                case AggregateType.MIN:
                    return DataType.Int;
                default:
                    return DataType.String;
            }
        }

        #endregion
    }
}
